package tasks

import java.io.BufferedReader
import java.io.FileReader
import java.util.regex.Pattern
import java.io.PrintWriter

case class EPModule(name: String, jsfilename: String, services: Seq[EPService]) {
  def toJavascript = """define([ 'ng', 'ngResource' ], function(angular) {
  var app=angular.module("""" ++ name ++ """Module", [ "ngResource" ]);
  app.factory("""" ++ name ++ """",function($resource) {
	var service = {};
""" ++ (services.map(_.toJavascript).mkString("\n")) ++ """
	return service;
  });
});"""
  def toJScala = """import jsmodels._
import traits.ArrayJs
    
trait """ ++ name ++ """EP {
""" ++ (services.map(_.toJScala).mkString("\n")) ++ """
}"""

}

case class EPService(method: String, url: String, name: String, params: Seq[String], responseType: String, bodyType: String) {

  def urlParamsSignature = "params:AnyRef{" + (params.foldLeft("")(_ ++ "var " ++ _ ++ ";")) ++ "}";

  def callbackSignature = "callback:(" ++ responseType ++ ")=>Unit";

  def starting = "def " ++ name ++ "(" ++ urlParamsSignature
  def ending = "):" ++ responseType ++ ";"
  def bodySignature = if (!method.equals("GET")) ",body:" + bodyType else ""
  def toJScala = starting ++ bodySignature ++ ending ++ "\n" ++ starting ++ bodySignature ++ "," ++ callbackSignature ++ ending;
  def toJavascript = "service." ++ name ++ "=$resource('" ++ url ++ "',{},{" ++ name ++ ":{method:'" ++ method ++ "',isArray:" ++ (if (responseType.startsWith("ArrayJs")) true else false).toString ++ "}})." + name;
}

//case class EPNonGet extends EPService

object GenerateEndPoints {

  def apply {
    val br = new BufferedReader(new FileReader("conf/newRoutes"));

    var line = nextLine(br);
    var modules = List[EPModule]();
    while (line match {
      case Some(_) => true
      case None => false
    }) {
      val lline = line.get;
      if (lline.startsWith("#MODULE")) {
        modules = createModule(lline.split("\\s+"), br) :: modules;
      }
      line = nextLine(br);
    }
    val pw = new PrintWriter("jscala/endPoints/EndPoints.scala");
    modules.foreach { x =>
      pw.println(x.toJScala)
      val jspw = new PrintWriter(x.jsfilename + ".js");
      jspw.println(x.toJavascript)
      jspw.close()
    }
    pw.close();
    br.close();
  }

  private def createModule(desc: Array[String], br: BufferedReader): EPModule = {

    var maybeLine = nextLine(br);

    var services = List[EPService]();

    while (maybeLine.map(!_.startsWith("#ENDMODULE")).getOrElse(false)) {
      val line = maybeLine.get;
      if (line.startsWith("#SERVICE")) {
        val serv = createService(line.replaceAll("#SERVICE\\s*", "").trim(), br)

        serv.foreach { serv =>
          services = serv :: services
        }

      }
      maybeLine = nextLine(br);
    }

    EPModule(desc(1), desc(2), services)
  }

  private def createService(desc: String, br: BufferedReader) = {

    // group 2 tiene los parametros

    nextLine(br).map(pattern.matcher)
      .filter(_.matches()).map { m =>

        val types = desc.split("\\s+");
        val url = m.group(2)
        val method = m.group(1);
        val name = m.group(3);
        val params = m.group(4).split(",").map(_.trim()).filter(_.length() > 0)
        EPService(method, url, name, params, types(0), types(1))

      }

  }

  val pattern = Pattern.compile("^(\\w+)\\s+([\\w/:]+)\\s+[\\w\\.]+?(\\w+?)\\((.*?)\\)$");
  def main(args: Array[String]) {
    GenerateEndPoints.apply

    //    val x = pattern.matcher("POST     /api/login                                                                                          controllers.UserCtrl.login()");
    //    println(x.matches());
  }
  def nextLine(br: BufferedReader): Option[String] = {
    try {
      var line = br.readLine().trim();
      while (line.length() == 0)
        line = br.readLine().trim();

      Some(line)

    } catch {
      case _: Throwable => None
    }
  }
}